package districting;

import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import com.vividsolutions.jts.geom.*;

import de.micromata.opengis.kml.v_2_2_0.AltitudeMode;
import de.micromata.opengis.kml.v_2_2_0.Document;
import de.micromata.opengis.kml.v_2_2_0.MultiGeometry;

public class PollingBooth {

   private String name;

   private int id;

   private State state;

   private Map<DivisionMethod, Division> division;

   private int totalVotesPrimary;

   private int totalVotes2PP;

   private Map<Candidate, Integer> resultsPrimary;

   private Candidate winnerPrimary;

   private int Labor2PPVotes;

   private Geometry polygon;

   private int Coalition2PPVotes;

   private Point point;

   public PollingBooth(String name, int id, State state, Point point,
         Division currDivision) {
      this.name = name;
      this.id = id;
      this.state = state;
      this.division = new HashMap<DivisionMethod, Division>();
      this.division.put(DivisionMethod.STATUS_QUO, currDivision);
      this.resultsPrimary = new HashMap<Candidate, Integer>();
      this.winnerPrimary = null;
      this.totalVotesPrimary = 0;
      this.totalVotes2PP = 0;
      this.point = point;
      // point = new
      // GeometryFactory().createPoint(location.convertToCoordinate());
      setPolygon(null);
   }

   /**
    * @return the division
    */
   public Division getDivision(DivisionMethod divMethod) {
      return division.get(divMethod);
   }

   /**
    * @param division
    *           the division to set
    */
   public void setDivision(Division division, DivisionMethod divMethod) {
      this.division.put(divMethod, division);
   }

   /**
    * @return the name
    */
   public String getName() {
      return name;
   }

   /**
    * @param name
    *           the name to set
    */
   public void setName(String name) {
      this.name = name;
   }

   /**
    * @return the resultsPrimary
    */
   public Map<Candidate, Integer> getResultsPrimary() {
      return resultsPrimary;
   }

   /**
    * @return the state
    */
   public State getState() {
      return state;
   }

   /**
    * @param state
    *           the state to set
    */
   public void setState(State state) {
      this.state = state;
   }

   /**
    * @return the id
    */
   public int getId() {
      return id;
   }

   /**
    * @param id
    *           the id to set
    */
   public void setId(int id) {
      this.id = id;
   }

   public int getTotalVotes() {
      /*
       * if (Math.abs(totalVotesPrimary - totalVotes2PP)>5) {
       * System.out.println("PB: " + name + ", Div: " + currDivision.getName() +
       * " Warning, Primary Votes: " + totalVotesPrimary + ", 2PP Votes: " +
       * totalVotes2PP); }
       */
      return totalVotes2PP;
   }

   public void addResultPrimary(Candidate candidate, int votes) {
      totalVotesPrimary += votes;
      resultsPrimary.put(candidate, votes);
      if (winnerPrimary == null || resultsPrimary.get(winnerPrimary) < votes) {
         winnerPrimary = candidate;
      }
   }

   public void addResult2PP(int LaborVotes, int CoalitionVotes) {
      Labor2PPVotes = LaborVotes;
      totalVotes2PP += LaborVotes;

      Coalition2PPVotes = CoalitionVotes;
      totalVotes2PP += CoalitionVotes;
   }

   public int getPrimaryVotes(Candidate c) {
      return resultsPrimary.get(c);
   }

   public Candidate getWinnerPrimary() {
      return winnerPrimary;
   }

   public void printResultsPrimary() {
      System.out.println(" printing resultsPrimary:");
      for (Candidate c : resultsPrimary.keySet()) {
         System.out.println("  " + c.getSurname() + " of " + c.getParty()
               + ": " + resultsPrimary.get(c));
      }
   }

   public void setPolygon(Geometry poly) {
      this.polygon = poly;
   }

   public Geometry getPolygon() {
      return polygon;
   }

   /**
    * @return the point
    */
   public Point getPoint() {
      return point;
   }

   public void createAndSetPlacemark(Document document) {
      de.micromata.opengis.kml.v_2_2_0.Placemark placemark = new de.micromata.opengis.kml.v_2_2_0.Placemark();

      String description = name + "\n"
            + "Total Votes = " + totalVotes2PP + "\n" + "Labor = "
            + (Labor2PPVotes / (float) totalVotes2PP * 100) + "%\n"
            + "Coalition = "
            + (Coalition2PPVotes / (float) totalVotes2PP * 100) + "%\n"
//            + "Primary Winner = " + winnerPrimary.getSurname() + " ("
//            + winnerPrimary.getParty().getName() + ")\n" 
            + "2PP Winner: "+ getWinner2PP().getName();
      document.createAndAddPlacemark().withStyleUrl("#balloonStyle").withDescription(description)
      .createAndSetPoint().addToCoordinates(point.getCoordinate().x, point.getCoordinate().y);
   }

   public de.micromata.opengis.kml.v_2_2_0.Polygon getPolygon(Polygon geom) {
      de.micromata.opengis.kml.v_2_2_0.Polygon new_polygon = new de.micromata.opengis.kml.v_2_2_0.Polygon();
      de.micromata.opengis.kml.v_2_2_0.LinearRing boundary = new de.micromata.opengis.kml.v_2_2_0.LinearRing();

      for (Coordinate coord : geom.getExteriorRing().getCoordinates()) {
         double x = coord.x;
         double y = coord.y;
         boundary.addToCoordinates(x, y);
      }
      new_polygon.createAndSetOuterBoundaryIs().setLinearRing(boundary);

      for (int i = 0; i < geom.getNumInteriorRing(); i++) {
         de.micromata.opengis.kml.v_2_2_0.LinearRing innerRing = new de.micromata.opengis.kml.v_2_2_0.LinearRing();
         for (Coordinate coord : geom.getInteriorRingN(i).getCoordinates()) {
            double x = coord.x;
            double y = coord.y;
            innerRing.addToCoordinates(x, y);
         }
         new_polygon.createAndAddInnerBoundaryIs().setLinearRing(innerRing);
      }
      return new_polygon;
   }

   public void toKml(Document document, Color color) {
      if (getPolygon() != null) {
         document.createAndAddStyle().withId(
               Zone.getHTMLColorString(getWinner2PP().getColor()))
               .createAndSetPolyStyle().withColor(
                     "7f" + Zone.getHTMLColorString(getWinner2PP().getColor()));
         createAndSetPlacemark(document);
         MultiGeometry multigeometry = document.createAndAddPlacemark()
               .withStyleUrl(
                     "#" + Zone.getHTMLColorString(getWinner2PP().getColor()))
               .createAndSetMultiGeometry();
         for (int i = 0; i < polygon.getNumGeometries(); i++) {
            multigeometry.addToGeometry(getPolygon((Polygon) polygon
                  .getGeometryN(i)));
         }
      }
   }

   /**
    * @return the Coalition2PPVotes
    */
   public int getCoalition2PPVotes() {
      return Coalition2PPVotes;
   }

   /**
    * @return the Labor2PPVotes
    */
   public int getLabor2PPVotes() {
      return Labor2PPVotes;
   }

   public Party getWinner2PP() {
      if (Coalition2PPVotes > Labor2PPVotes) {
         return Nation.COALITION;
      } else {
         return Nation.LABOR;
      }
   }

   public Geometry getGeometryPoint() {
      return point;
   }

   /*
    * (non-Javadoc)
    * 
    * @see java.lang.Object#hashCode()
    */
   @Override
   public int hashCode() {
      final int PRIME = 31;
      int result = super.hashCode();
      result = PRIME * result + id;
      return result;
   }

   /*
    * (non-Javadoc)
    * 
    * @see java.lang.Object#equals(java.lang.Object)
    */
   @Override
   public boolean equals(Object obj) {
      if (this == obj)
         return true;
      if (!super.equals(obj))
         return false;
      if (getClass() != obj.getClass())
         return false;
      final PollingBooth other = (PollingBooth) obj;
      if (id != other.id)
         return false;
      return true;
   }

}
